# D115 Tags
from django import template
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.template.defaultfilters import stringfilter
from django.utils.encoding import smart_unicode
from django.utils.html import *
from django.utils.safestring import mark_safe
from d115.utils.listutils import tuplify as l_tpl, collides
from datetime import datetime
import re 

register = template.Library()

@register.filter
def percentage(fraction, population):
    try:
        return "%.2f%%" % ((float(fraction) / float(population)) * 100 )
    except:
        return ''

@register.filter
def replace(string, args):
    return unicode(string).replace(args[0], args[1])

@register.filter
def tuplify(a_list, n=3):
    try:
        n = int(n)
    except:
        n = 3
    return l_tpl(a_list, n)

@register.filter
def wordbreak(string, arg):
    search = '([^ ]{' + arg + '})'
    t = datetime.now()
    wbr = t.strftime("%A%d%B%Y%f") + 'wbr_here' + t.strftime("%A%d%B%Y%f")
    #saferesult = conditional_escape(re.sub( search, '\\1' + wbr, string ))
    saferesult = re.sub( search, '\\1' + wbr, string )
    result = saferesult.replace(wbr,'&shy; ')
    return mark_safe(result)

@register.inclusion_tag('d115/pagination.html')
def pagination(page, q=None, begin_pages=2, end_pages=2, before_current_pages=4, after_current_pages=4):
    before = max(page.number - before_current_pages - 1, 0)
    after = page.number + after_current_pages

    begin = page.paginator.page_range[:begin_pages]
    middle = page.paginator.page_range[before:after]
    end = page.paginator.page_range[-end_pages:]
    last_page_number = end[-1]

    if collides(middle, end):
        end = range(max(last_page_number - before_current_pages - after_current_pages, 1), last_page_number+1)
        middle = []

    if collides(begin, middle):
        begin = range(1, min(before_current_pages + after_current_pages, last_page_number)+1)
        middle = []

    if collides(begin, end):
        begin = range(1, last_page_number+1)
        end = []

    return locals()

def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False, target=None):
    trim_url = lambda x, limit=trim_url_limit: limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x
    safe_input = isinstance(text, SafeData)
    words = word_split_re.split(force_unicode(text))
    nofollow_attr = nofollow and ' rel="nofollow"' or ''
    target_attr = (" target='%s'" % target) if target else ''
    for i, word in enumerate(words):
        match = None
        if '.' in word or '@' in word or ':' in word:
            match = punctuation_re.match(word)
        if match:
            lead, middle, trail = match.groups()
            # Make URL we want to point to.
            url = None
            if middle.startswith('http://') or middle.startswith('https://'):
                url = urlquote(middle, safe='/&=:;#?+*')
            elif middle.startswith('www.') or ('@' not in middle and \
                    middle and middle[0] in string.ascii_letters + string.digits and \
                    (middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))):
                url = urlquote('http://%s' % middle, safe='/&=:;#?+*')
            elif '@' in middle and not ':' in middle and simple_email_re.match(middle):
                url = 'mailto:%s' % middle
                nofollow_attr = ''
                target_attr = ''
            # Make link.
            if url:
                trimmed = trim_url(middle)
                if autoescape and not safe_input:
                    lead, trail = escape(lead), escape(trail)
                    url, trimmed = escape(url), escape(trimmed)
                middle = '<a href="%s"%s%s>%s</a>' % (url, nofollow_attr, target_attr, trimmed)
                words[i] = mark_safe('%s%s%s' % (lead, middle, trail))
            else:
                if safe_input:
                    words[i] = mark_safe(word)
                elif autoescape:
                    words[i] = escape(word)
        elif safe_input:
            words[i] = mark_safe(word)
        elif autoescape:
            words[i] = escape(word)
    return u''.join(words)
urlize = allow_lazy(urlize, unicode)

def html_urlize(value, autoescape=None):
    from BeautifulSoup import BeautifulSoup
    ignored_tags = ['a','code','pre']
    soup = BeautifulSoup(value)
    tags = soup.findAll(True)
    text_all = soup.contents
    for text in text_all:
        if text not in tags:
            parsed_text = urlize(text, nofollow=True, autoescape=autoescape)
            text.replaceWith(parsed_text)
    for tag in tags:
        if not tag.name in ignored_tags:
            soup_text = BeautifulSoup(str(tag))
            if len(soup_text.findAll()) > 1:
                for child_tag in tag.contents:
                    child_tag.replaceWith(html_urlize(smart_unicode(child_tag)))
            elif len(soup_text.findAll()) > 0:
                text_list = soup_text.findAll(text=True)
                for text in text_list:
                    parsed_text = urlize(text, nofollow=True, autoescape=autoescape)
                    text.replaceWith(smart_unicode(soup_text))
                try:
                    tag.replaceWith(smart_unicode(soup_text))
                except:
                    pass
    return mark_safe(smart_unicode(soup))
html_urlize.is_safe = True
html_urlize.needs_autoescape = True
html_urlize = stringfilter(html_urlize)
register.filter(html_urlize)

@register.filter("urlize_html")
def urlize_html(html):
    """
    Returns urls found in an (X)HTML text node element as urls via Django urlize filter.
    """
    try:
        from BeautifulSoup import BeautifulSoup
    except ImportError:
        if settings.DEBUG:
            raise template.TemplateSyntaxError, "Error in urlize_html The Python BeautifulSoup libraries aren't installed."
        return html
    else:
        soup = BeautifulSoup(html)
           
        textNodes = soup.findAll(text=True)
        for textNode in textNodes:
            urlizedText = urlize(textNode, target="_blank")
            textNode.replaceWith(urlizedText)
            
        return str(soup)
urlize_html.is_safe = True

class RangeNode(template.Node):
    def __init__(self, parser, range_args, context_name):
        self.template_parser = parser
        self.range_args = range_args
        self.context_name = context_name

    def render(self, context):

        resolved_ranges = []
        for arg in self.range_args:
            compiled_arg = self.template_parser.compile_filter(arg)
            resolved_ranges.append(compiled_arg.resolve(context, ignore_failures=True))
        context[self.context_name] = range(*resolved_ranges)
        return ""
        
@register.tag
def mkrange(parser, token):
    """
    Accepts the same arguments as the 'range' builtin and creates
    a list containing the result of 'range'.
    
    Syntax:
        {% mkrange [start,] stop[, step] as context_name %}

    For example:
        {% mkrange 5 10 2 as some_range %}
        {% for i in some_range %}
          {{ i }}: Something I want to repeat\n
        {% endfor %}
    
    Produces:
        5: Something I want to repeat 
        7: Something I want to repeat 
        9: Something I want to repeat 
    """

    tokens = token.split_contents()
    fnctl = tokens.pop(0)

    def error():
        raise template.TemplateSyntaxError, "%s accepts the syntax: {%% %s [start,] " +\
                "stop[, step] as context_name %%}, where 'start', 'stop' " +\
                "and 'step' must all be integers." %(fnctl, fnctl)

    range_args = []
    while True:
        if len(tokens) < 2:
            error()

        token = tokens.pop(0)

        if token == "as":
            break

        range_args.append(token)
    
    if len(tokens) != 1:
        error()

    context_name = tokens.pop()

    return RangeNode(parser, range_args, context_name)
